package geo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class DownloadZxyMapTile {

    static ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 16,
            10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000), new ThreadPoolExecutor.CallerRunsPolicy());

    final static int EPSG3857 = 1;
    final static int WMTS = 2;

    public static void main(String[] args) throws InterruptedException {
//        String tileUrl = "http://webst0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}";
//        String[] subdomains = {"1", "2", "3", "4"};
//        String storeDir = "D:/project/titlemap/gaode/{z}/{x}/";
//
//        downloadTiles(1, 9, tileUrl, storeDir, subdomains, EPSG3857);

//        String tileUrl = "http://t{s}.tianditu.gov.cn/cta_c/wmts?TileMatrix={z}&TileCol={y}&TileRow={x}&layer=cta&style=default&tilematrixset=c" +
//                "&service=wmts&request=getTile&version=1.0.0&format=tiles&tk=3218e1d28ef9e4ecc944b4c58a51c745";
//        String[] subdomains = {"0", "1", "2", "3", "4", "5", "6", "7"};
//        String storeDir = "D:/project/titlemap/tiandituText/{z}/{x}/";
//
//        downloadTiles(2, 7, tileUrl, storeDir, subdomains, WMTS);

        String tileUrl = "http://t{s}.tianditu.gov.cn/cta_w/wmts?TileMatrix={z}&TileCol={y}&TileRow={x}" +
                "&style=default" +
                "&layer=cta" +
                "&tilematrixset=w" +
                "&service=wmts&request=getTile&version=1.0.0&format=tiles&tk=3218e1d28ef9e4ecc944b4c58a51c745";
        String[] subdomains = {"0", "1", "2", "3", "4", "5", "6", "7"};
        String storeDir = "D:/project/titlemap/tiandituText3857/{z}/{x}/";

        downloadTiles(2, 7, tileUrl, storeDir, subdomains, WMTS);
    }

    public static void downloadTiles(int minZoom, int maxZoom, String tileUrl, String storeDir, String[] subdomains, int srs) throws InterruptedException {
        long start;
        System.out.println("开始: " + (start=System.currentTimeMillis()));
        for (int z = minZoom; z <= maxZoom; z++) {
            System.out.println("z:" + z);
            if (srs == EPSG3857) {
                downloadEPSG3857TileByZoom(z, tileUrl, storeDir, subdomains);
            } else if (srs == WMTS) {
                downloadEPSG4326TileByZoom(z, tileUrl, storeDir, subdomains);
            }
        }
        while (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
            System.out.println("停止，耗时：" + (System.currentTimeMillis() - start) + "ms");
            executor.shutdown();
        }
    }

    public static void downloadEPSG3857TileByZoom(int destZoom, String tileTemplateUrl, String storeDir, String[] subdomains) {
        Random random = new Random();

        int num = (int) Math.pow(2, destZoom);
        String z = String.valueOf(destZoom);
        for (int x = 0; x < num; x++) {
            String xStr = String.valueOf(x);

            String tileXDir = storeDir.replace("{z}", z).replace("{x}", xStr);
            new File(tileXDir).mkdirs();

            for (int y = 0; y < num; y++) {
                downloadFileByZxy(tileTemplateUrl, tileXDir, xStr, String.valueOf(y), z, subdomains, random);
            }
        }
    }

    public static void downloadEPSG4326TileByZoom(int destZoom, String tileTemplateUrl, String storeDir, String[] subdomains) {
        Random random = new Random();

        int xMax = (int) Math.pow(2, destZoom - 1);
        int yMax = xMax * 2;
        String z = String.valueOf(destZoom);
        for (int x = 0; x < xMax; x++) {
            String xStr = String.valueOf(x);

            String tileXDir = storeDir.replace("{z}", z).replace("{x}", xStr);
            new File(tileXDir).mkdirs();

            for (int y = 0; y < yMax; y++) {
                downloadFileByZxy(tileTemplateUrl, tileXDir, xStr, String.valueOf(y), z, subdomains, random);
            }
        }
    }

    public static void downloadFileByZxy(String tileTemplateUrl, String tileXDir, String x, String y, String z, String[] subdomains, Random random) {
        File tileFile = new File( tileXDir + y + ".png");
        if (!tileFile.exists()) {
            String tileUrlTmp = tileTemplateUrl;
            if (subdomains != null) {
                String subdomain = subdomains[random.nextInt(subdomains.length)];
                tileUrlTmp = tileUrlTmp.replace("{s}", subdomain);
            }
            tileUrlTmp = tileUrlTmp.replace("{x}", x)
                    .replace("{y}", String.valueOf(y))
                    .replace("{z}", z);
            final String tileUrlF = tileUrlTmp;
            executor.execute(() -> {
                downloadFile(tileUrlF, tileFile);
            });
        }
    }

    public static void downloadFile(String fileUrl, File destFile) {
        InputStream inputStream = null;
        FileOutputStream out = null;
        try {
            URL url = new URL(fileUrl);
            URLConnection conn = url.openConnection();

            conn.setConnectTimeout(10000);
            conn.setReadTimeout(10000);
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "close");
            conn.setRequestProperty("user-agent",
                    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36");


            inputStream = conn.getInputStream();

            out = new FileOutputStream(destFile);
            int j;
            while ((j = inputStream.read()) != -1) {
                out.write(j);
            }

        } catch (Exception e) {
            System.out.println("下载失败：" + fileUrl);
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
